<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<link rel="stylesheet" href="./document.css" type="text/css">
<title>SpringProxEX API - Working with more than one CSB at a time</title>
</head>
<body bgcolor="#FFFFFF">
<h1>SpringProxEX API - Working with more than one CSB at a time</h1>
<h3>Abstract</h3>
<p>SpringCard API makes it easy to work with a CSB or other SpringProx family reader, using simple function calls.</p>
<p>One of the key aspects of SpringProx API is in the lack of pointer or handle to identify the device, as the API assumes that the application
works with only one device at once. It some cases, this limitation must be overcomed, typically when one single PC-based application is in charge
of numerous devicess.</p>
<p>This documents introduces &laquo;&nbsp;SpringProxEX&nbsp;&raquo; API, which make it possible to do so.</p>
<h3>Audience</h3>
<p>This document assumes that the reader has a good knowledge of SpringProx API. Always refer to
<a href="../springprox_api/index.html">SpringProx API documentation</a> for details regarding function parameters, and usage.</p>

<h2>Step-by-step guide to migrate native applications</h2>

<p>In this chapter we'll see how a typicall application (C or C++) can switch from SpringProx API to SpringProxEX API.</p>

<h3>Replace springprox header by springprox_ex</h3>

<p>SpringProxEX API functions are protyped in <b>springprox_ex.h</b>. Replace C or C++ lines <tt>#include &lt;sprinprox.h&gt;</tt>
by <tt>#include &lt;sprinprox_ex.h&gt;</tt> in your source code</p>

<p>Note that <b>springprox_ex.h</b> refers to <b>springprox.h</b> (e.g. includes it) for compatibility and convenience.</p>

<h3>Create an instance for each device</h3>

<p>Each CSB (or SpringProx compliant reader) will be associated to a distinct <b>SPROX_INSTANCE</b> object. Use <b>SPROXx_CreateInstance</b> function
to instantiate the objects, as follow&nbsp;:</p>

<pre>
  /* Allocate 3 instances, to work with 3 CSB readers */
  SPROX_INSTANCE arInst[3];
  int i;
  
  for (i=0; i<3; i++)
  {
    arInst[i] = SPROXx_CreateInstance();
    if (arInst[i] == NULL)
    {
      /* Fatal error, raise an exception or leave the procedure here */
      return FALSE;
    }  
  }  
</pre>

<h3>Get access to the devices</h3>

<p>Just as you call <b>SPROX_ReaderOpen</b> to get access to your CSB, call <b>SPROXx_ReaderOpen</b> to get access (note the plural !)
to the 2 or more readers.</p>

<p>There're three different ways to select the reader to be opened.</p>

<h4>No explicit selection</h4>

<p>In this case we use the &laquo;&nbsp;automatic detection&nbsp;&raquo; feature, where the library tries to connect to the first available
reader. Detection is done in this order&nbsp;:</p>
<ul>
  <li>Lookup for USB-connected readers (using FTDI D2XX driver and library),</li>
  <li>Lookup for serial-connected readers, from COM1 to COM9.</li>
</ul>

<p>Here's the sample source code&nbsp;:</p>

<pre>
  SWORD rc;
  BOOL reader_found[3] = { FALSE };
  
  for (i=0; i<3; i++)
  {
    rc = SPROXx_ReaderOpen(arInst[i], NULL);
    if (rc == MI_OK)
    {
      /* OK, reader connected to this instance */
      reader_found[i] = TRUE;
    }  
  }  
</pre>

<p>The major advantage of this method is its ease of use&nbsp;: there's no need to store any configuration data related to a list of readers.</p>

<p>One disadvantage is the time taken by the discovery loop&nbsp;: for every existing serial communication device (COM1 to COM9) with no reader
attached, SPROXx_ReaderOpen function will block for 2 to 4 seconds until returning an error.</p>

<p>Another disadvantage is that there's no guarantee regarding the order of the USB discovery loop&nbsp; in other words, if you have 2 (or more)
CSB readers connected to USB ports of your computer, you have no way to know which SpringProxEX instance is associated to which physical device.</p>

<h4>Explicit selection through serial port</h4>

<p>In this case the application has to provide a list of ports, the CSB are connected to. They can either be real serial ports or virtual
ports (USB or PCMCIA/CompactFlash bridge).</p>

<p>Here's the sample source code&nbsp;:</p>

<pre>
  SWORD rc;
  BOOL reader_found[3] = { FALSE };
  
  /* To be provided by application */
  const char *reader_ports[3] = {
    "COM2",            // First device is connected to COM2
    "COM7",            // Second device is connected to COM7
    "\\\\.\\COM12"     // Third device is connected to COM12.
                       // Note that we MUST write \\.\COM12 (and double the anti-slash in C or C++)
                       // as Windows expects serial devices above 10 to be named this way.
  };
  
  for (i=0; i<3; i++)
  {
    rc = SPROXx_ReaderOpen(arInst[i], reader_ports[i]);
    if (rc == MI_OK)
    {
      /* OK, reader connected to this instance */
      reader_found[i] = TRUE;
    }  
  }  
</pre>

<p>The major advantage is that we know for sure the relationship between physical device and SpringProx EX instance.</p>

<p><small>For sure ? Well, it depends... Generally speaking, yes, but with USB devices it is possible to play with driver parameters
(in device manager) and have the devices taking different virtual comm port numbers than expected.</small></p>

<h4>Explicit selection through USB identifiers</h4>

<p>This method is applicable only to</p>
<ul>
  <li>CSB4U (or CSB5U) devices,</li>
  <li>With FTDI D2XX (or CDM) driver (VCP doesn't allow it).</li>
</ul>

<p>In this case the application has to provide the list of CSB identifiers (use <b>ref_usbenum.exe</b> from the SDK to get this list, or
read the numbers from product's identification label).</p>
<p><small>Source code ref_usbenum.c is provided in the SDK, making it easy to add the enumeration process in your own application.</small></p>

<p>Here's the sample source code&nbsp;:</p>

<pre>
  SWORD rc;
  BOOL reader_found[3] = { FALSE };
  
  /* To be provided by application */
  const char *reader_idents[3] = {
    "USB:PA001234",    // Serial number of first device, prefixed with "USB:"
    "USB:PA005678",    // Serial number of second device, prefixed with "USB:"
    "USB:PA010155"     // Serial number of third device, prefixed with "USB:"
  };
  
  for (i=0; i<3; i++)
  {
    rc = SPROXx_ReaderOpen(arInst[i], reader_idents[i]);
    if (rc == MI_OK)
    {
      /* OK, reader connected to this instance */
      reader_found[i] = TRUE;
    }  
  }  
</pre>

<p>The major advantage is that we know for sure the relationship between physical device and SpringProx EX instance.</p>
<p><small>For sure ? Yes, for sure !</small></p>

<h3>Work with the devices</h3>

<p>Just as SpringProx API functions are called <tt>SPROX_...</tt>, SpringProxEX API functions are called <tt>SPROXx_...</tt>. Function prototypes
are generally speaking identical, only first parameter <tt>SPROX_INSTANCE rInst</tt> must be provided to every function call.</p>

<p>Here's a few examples&nbsp;:</p>

<table width="100%">
  <tr>
    <th width="50%">SpringProx</th>
    <th width="50%">SpringProxEX</th>
  </tr>
  <tr>
    <td><pre>
      // LEDs : red is on, green is blinking
      SPROX_ControlLed(1, 2);    
    </pre></td>
    <td><pre>
      // LEDs : red is on, green is blinking
      SPROXx_ControlLed(rInst, 1, 2);            
    </pre></td>
  </tr>
  <tr>
    <td><pre>
      // Select an ISO 14443-A card
      SPROX_A_SelectAny(atq, snr, &snrlen, sak);
    </pre></td>
    <td><pre>
      // Select an ISO 14443-A card
      SPROXx_A_SelectAny(rInst, atq, snr, &snrlen, sak);
    </pre></td>
  </tr>    
  <tr>
    <td><pre>
      // Halt the selected card
      SPROX_A_Halt();
    </pre></td>
    <td><pre>
      // Halt the selected card
      SPROXx_A_Halt(rInst);
    </pre></td>
  </tr>  
</table>

<p>As you can see, existing function SpringProx calls must be rewritten as SpringProxEX function calls. At the end of the migration process,
every call to <tt>SPROX_...</tt> must have been replaced by its <tt>SPROXx_...</tt> equivalent.</p>

<h3>Cleanup everyhing when exiting</h3>

<p>Just as you created an instance for each device, then got access to it, the application must close access and free the instance before exiting.</p>
<p>Use <b>SPROXx_ReaderClose</b> and <b>SPROXx_DestroyInstance</b> to do so.

<pre>
  /* Terminate 3 instances */
  for (i=0; i<3; i++)
  {  
    if (reader_active[i])
      SPROXx_ReaderClose(arInst[i]);
    SPROXx_DestroyInstance(arInst[i]);
    arInst[i] = NULL; // Safety line...
  }
</pre>

<h3>Link with SpringProxEX API</h3>

<p>Now that your source code has been modified to use SpringProxEX API, it's time to replace <b>springprox.lib</b> (that contains the entry points
for <b>springprox.dll</b>) by <b>springprox_ex.lib</b> (that contains the entry points for <b>springprox_ex.dll</b>).</p>

<p>Don't forget to distribute <b>springprox_ex.dll</b> with your application, instead of <b>springprox.dll</b>.</p>

<h2>A few hints and advices</h2>

<h3>Multi-threading and performance issue</h3>

<p><b>SpringProxEX API</b> is a thread safe library (a thread associated to instance arInst[0] will never block waiting for instance arInst[1]
or arInst[2]). As with any multi-threaded application working with hardware, we can come to a bottleneck when the USB subsystem is heavily loaded.
When performing active polling (loop over SPROXx_A_SelectAny typically), allow other threads to run by adding a delay in the loop&nbsp:

<pre>
  /* Instance is waiting for a card */
  SWORD rc;
  
  for (;;)
  {
    rc = SPROXx_A_SelectAny(rInst, atq, snr, &snrlen, sak);
    if (rc == MI_OK)
      break;   // Card found !!!

    Sleep(30); // Going to sleep mode explicitly gives other threads with the same priority
               // more chances to perform their "important" job quickly, where this thread is
               // still doing nothing important.
  }
</pre>

<h3>The <b>SPROX_INSTANCE</b> type</h3>

<p><b>SPROX_INSTANCE</b> is an abstract data type, i.e. a pointer to an incomplete type&nbsp;<tt>typedef struct _SPROX_CTX_ST *SPROX_INSTANCE</tt>.</p>

<p>If your compiler doesn't allow this syntax, you may replace it by a <tt>#define SPROX_INSTANCE void*</tt>.</p>

<p>For other languages (VB, Delphi) or other environment (.NET typically), <tt>SPROX_INSTANCE</tt> must be a native pointer type (<tt>pointer</tt> for Delphi,
<tt>System.IntPtr</tt> for .NET).</p>

</body>
</html>
